//for PHP private connection server to server
const PHP_KEY = 'KNCa3FrpSY4IEvIpVHLmAOwhOF7QWCPIOa52glVQQw8Sniv7Of8s7WTXmUKuI0Cg';

/**
 * Establish MySQL Connection
 
var mysql = require('mysql');

var client = mysql.createConnection({
    host : 'facecom.local',
    user : 'root',
    password : '@dm1n'
});
client.connect();
client.query('USE facecom');
client.query("SET NAMES 'utf8'");
//*End connection establishing*/

var io = require('socket.io').listen(10010);

var users = {};
var timers = {};
var user_friends = {};
var friends_of = {};

var chat = io
.of('/chat')
.on('connection', function (socket) {

    /**
     * Setup a new connection
     * Add user info, friends info, etc to the connected socket namespace
     */
    socket.on('setup',function(data){
        var key = data.key.split('x1x');
        var user_id = key.pop();
        var log = '';
        key = key.join('x1x');
        log = 'Setting up data for '+data.key;
        if(timers.hasOwnProperty(data.key)){
            clearTimeout(timers[data.key]);
            delete timers[data.key];
        }
        if(!users[data.key] || users[data.key] == null){
            users[data.key] = socket;
            var mongo = require('mongodb'),
            Server = mongo.Server,
            BSON = mongo.BSONPure,
            Db = mongo.Db;

            var mongoDb = new Server('localhost', 27017, {
                auto_reconnect: true
            });
            var db = new Db('facecom', mongoDb);            
            //tell everyone that you are online
            db.open(function(err,db){
                if(!err){
                    db.collection('messages',function(err,collection){
                        for(k in data.friends){
                            if(!err){
                                collection.find({to:user_id,from:data.friends[k],hasRead:0}).toArray(function(err,cur){
                                    var cnt = cur.length;
                                    if(!err && cnt>0){
                                        socket.emit('count',{id:cur[0].from,count:cnt});
                                    }
                                })
                            }else{
                                console.log("\033[1;31m"+err+"\033[0m");
                            }
                            if(users.hasOwnProperty(k)){
                                users[k].emit('status',{id:user_id,status:1})
                            }
                        }
                        db.close();
                    })
                }else
                    console.log("\033[1;31m"+err+"\033[0m");
            })
            socket.set('user',{key:key,id:user_id,friends:data.friends},function(){
                log+="(user_id#"+user_id+")......................\033[1;32mOK!\033[0m";
            });        
        }else{
            log+="......................\033[1;31mFAIL!!!!\033[0m";
        }
        console.log(log);log='';
    })
    socket.on('publish',function(data){
        if(
                //!users[data.key] || //<--- if friend is offline you cannot send messages to him, 'cause conditions doesn't pass
                !data.message || typeof data.message != 'string')
            return false;
        var san = require('validator').sanitize;
        var msg = san(data.message).trim();
        var mongo = require('mongodb'),
        Server = mongo.Server,
        BSON = mongo.BSONPure,
        Db = mongo.Db;

        var mongoDb = new Server('localhost', 27017, {
            auto_reconnect: true
        });
        var db = new Db('facecom', mongoDb);        
        if(msg!=''){
            socket.get('user',function(err,user){
                msg = san(msg).entityEncode();
                msg = san(msg).xss();
                msg = msg.toString().slice(0,255);
                //TODO: not sure on using users[data.key].store.data... in direct access. check on a battlefield
                //friends test
                if(user != null && user.friends.hasOwnProperty(data.key) 
//                        && users[data.key].store.data.hasOwnProperty('user') //<--- if friend is offline you cannot send messages to him, 'cause conditions doesn't pass
//                        && users[data.key].store.data.user.friends.hasOwnProperty(user.key+'x1x'+user.id)
                ){
                    db.open(function(err,db){
                        if(!err){
                            db.collection('messages',function(err,collection){
                                if(!err){
                                    var id = data.key.split('x1x').pop();
                                    var time = new Date().getTime();
                                    var doc = {text:msg,from:user.id,to:id,time:time,hasRead:0};
                                    collection.insert(doc,function(err,item){
                                        if(!!users[data.key])
                                            users[data.key].emit('publish',{msg:msg,id:user.id,time:time,hasRead:0,mid:item[0]._id,key:data.key});
                                        db.close();
                                    })
                                }else
                                    console.log("\033[1;31m"+err+"\033[0m");
                            })
                        }else
                            console.log("\033[1;31m"+err+"\033[0m");
                    });
                }
            })
        }
    })
    socket.on('has read',function(data){
        var mongo = require('mongodb'),
        Server = mongo.Server,
        BSON = mongo.BSONPure,
        Db = mongo.Db;

        var mongoDb = new Server('localhost', 27017, {
            auto_reconnect: true
        });
        var db = new Db('facecom', mongoDb);        
        db.open(function(err,db){
            if(!err){
                db.collection('messages',function(err,collection){
                    if(!err){
                        collection.update({_id:BSON.ObjectID(data.id)},{'$set':{hasRead:1}},{upsert:false,multi:false},function(err,item){})
                        db.close();
                    }else
                        console.log("\033[1;31m"+err+"\033[0m");
                })
            }else
                console.log("\033[1;31m"+err+"\033[0m");
        });
    })
    socket.on('iamonline',function(data){
        socket.get('user',function(err,user){
            for(k in user.friends){
                if(users.hasOwnProperty(k)){
                    users[k].emit('line',{id:user.id,status:1})
                }                
            }
        })
    })
    socket.on('get messages',function(data){
        if(data!=null && data.hasOwnProperty('key'))
        socket.get('user',function(err,user){
            //is in friends
            if(user!=null && user.friends.hasOwnProperty(data.key)){
                var mongo = require('mongodb'),
                Server = mongo.Server,
                BSON = mongo.BSONPure,
                Db = mongo.Db;

                var mongoDb = new Server('localhost', 27017, {
                    auto_reconnect: true
                });
                var db = new Db('facecom', mongoDb);                
                db.open(function(err,db){
                    if(!err){
                        db.collection('messages',function(err,collection){
                            if(!err){
                                var id = user.friends[data.key];//data.key.split('x1x').pop();
                                var query = {'$or':[{'from':user.id,'to':id},{'from':id,'to':user.id}]};
                                var today = 0;
                                //demand older messages
                                if(data.hasOwnProperty('day') && data.day<31 && data.day>0){
                                    today = parseInt(new Date().getTime()-84600000);
                                    today = today - 84600000 * data.day;
                                    query.time = {'$gt':today};
                                    collection.find({'$query':query,'$orderby':{'time':1}}).toArray(function(err,items){
                                        if(!err){
                                            socket.emit('messages',{id:user.friends[data.key],key:data.key,messages:items})
                                            collection.update(query,{'$set':{hasRead:1}},{upsert:false,multi:true});
                                            db.close();
                                        }else
                                            console.log("\033[1;31m"+err+"\033[0m");
                                    });
                                }else{
                                    //get from last unread message
                                    collection.findOne({'$query':{'hasRead':0},'$orderby':{'time':-1}},function(err,result){
                                        today = new Date().getTime() - 84600000;
                                        if(!err && !!result){
                                            if(result.time<today)
                                                today = result.time-10000;
                                        }
                                        //today = parseInt(new Date(today.getFullYear()+'-'+(today.getMonth()+1)+'-'+today.getDate()+'T00:00').getTime());
                                        query.time = {'$gt':today};
                                        collection.find({'$query':query,'$orderby':{'time':1}}).toArray(function(err,items){
                                            if(!err){
                                                socket.emit('messages',{id:user.friends[data.key],messages:items})
                                                collection.update({from:id,to:user.id,time:{'$gt':today}},{'$set':{hasRead:1}},{upsert:false,multi:true});
                                                db.close();
                                            }else
                                                console.log("\033[1;31m"+err+"\033[0m");
                                        });
                                    })
                                }
                            }else
                                console.log("\033[1;31m"+err+"\033[0m");
                        })
                    }else
                        console.log("\033[1;31m"+err+"\033[0m");
                })
            }
        })        
    })

    socket.on('disconnect',function(){
        var log = '';
        socket.get('user',function(err,user){
            if(user!=null && user.hasOwnProperty('key'))
                log = user.key+'x1x'+user.id + ' trying to disconnect';
            if(user!=null && user.hasOwnProperty('key')){
                //tell everyone that you disconnected
                for(key in user.friends){
                    if(users.hasOwnProperty(key)){
                        users[key].emit('status',{id:user.id,status:0})
                    }
                }
                delete users[user.key+'x1x'+user.id];
                log += '.....................OK!';
            }else
                log += '.....................FAIL!';
            console.log(log);
        })
    });    
})

/**
 * Server connection for data transfer purpose
 * Data transfer must be json and with key attribute, containing private key
 */
var php = io.sockets
.on('connection',function(socket){
    socket.on('data',function(data){
        if(data.key === PHP_KEY){
            
        }
    })
})


        //not needed yet
        /*
        client.query('SELECT id,activation_key FROM user WHERE id IN (SELECT friend_id FROM user_friends WHERE status=1 AND user_id = (SELECT id FROM users WHERE id='+user_id+' AND activation_key'+key+'))', function(error, result, fields){
            if (error){
                socket.send(error);
                socket.disconnect();
                return false;
            }
            var friends = {};
            for(i in result){
                friends[result[i].id] = result[i].activation_key
                var md5 = '';
                if(result[i].id<user_id)
                    md5 = require('crypto').createHash('md5').update(result[i].id+'speaksWith'+user_id).digest('hex');
                else
                    md5 = require('crypto').createHash('md5').update(user_id+'speaksWith'+result[i].id).digest('hex');
                socket.emit('subscribe',{user_id:result.id,key:md5});        
                socket.on(md5,function(data){
                    socket.emit(md5,data)
                })
            }
            //TODO: notify friends that user is connected
            socket.set('friends',data,function(){
                socket.send('ready');
            });
        });*/
